# log_utils.py
import logging
import asyncio
import sys

class CoroutineFormatter(logging.Formatter):
    """协程任务名称注入日志格式化器"""
    def format(self, record):
        try:
            task = asyncio.current_task()
            task_name = task.get_name() if task else "Main"
            task_count = len(asyncio.all_tasks())
            record.coroutine_name = f"{task_name}({task_count})"
        except RuntimeError:
            record.coroutine_name = None
        return super().format(record)
class AsyncLogger:
    """异步日志封装类"""
    _instance = None

    def __new__(cls, *args, **kwargs):
        if not cls._instance:
            cls._instance = super().__new__(cls)
            cls._instance._init_logger()
        return cls._instance

    def _init_logger(self):
        """初始化日志配置"""
        self.logger = logging.getLogger("AsyncLogger")
        self.logger.setLevel(logging.INFO)

        # 创建控制台处理器
        handler = logging.StreamHandler(sys.stdout)
        handler.setLevel(logging.INFO)

        # 设置自定义格式
        formatter = CoroutineFormatter(
            "%(asctime)s [%(levelname)s] "
            "[线程-%(threadName)s] "
            "[协程-%(coroutine_name)s] "
            "%(message)s"
        )
        handler.setFormatter(formatter)

        # 清理已有处理器避免重复
        if self.logger.handlers:
            for handler in self.logger.handlers[:]:
                self.logger.removeHandler(handler)

        self.logger.addHandler(handler)

    def debug(self, msg):
        self.logger.debug(f"{msg}")

    def info(self, msg):
        self.logger.info(f"{msg}")

    def warning(self, msg):
        self.logger.warning(f"{msg}")

    def error(self, msg):
        self.logger.error(f"{msg}")

    def critical(self, msg):
        self.logger.critical(f"{msg}")

    @staticmethod
    def _get_caller_info():
        """获取调用位置信息"""
        import inspect
        stack = inspect.stack()
        frame = stack[3] if len(stack) > 3 else stack[2]
        return f"{frame.filename}:{frame.lineno}"

# 使用示例
if __name__ == "__main__":
    logger = AsyncLogger()
    logger.info("测试日志输出")